#include "ViewModel.h"
#include "View.h"
#include <stdbool.h>
#include <stdio.h>
#define N_CMD 8
#define X_BTN 13
#define Y_BTN 3

HANDLE hIn;
HANDLE hOut;
int pageIndex = 0;
//按钮的左/上锚点
const short POS_X[4] = {1, 15, 29, 43};
const short POS_Y[2] = {21, 24};
//返回按钮的锚点
const short X_RETURN = 43;
const short Y_RETURN = 24;

static const void (*command[N_CMD])() =
{
    showPageSearch, showPageSort, showPageWrite, showPageDelete,
    showPageDeposit, showPageWithdraw, showPageTransfer, cmdExit
};

void initView()
{
    SetConsoleCP(CP_UTF8);
    SetConsoleOutputCP(CP_UTF8);
    SetConsoleTitleA("账户管理系统");
    hIn = GetStdHandle(STD_INPUT_HANDLE);
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    DWORD mode;
    GetConsoleMode(hIn, &mode);
    mode &= ~ENABLE_QUICK_EDIT_MODE;
    mode &= ~ENABLE_INSERT_MODE;
    mode |= ENABLE_MOUSE_INPUT;
    mode |= ENABLE_EXTENDED_FLAGS;
    SetConsoleMode(hIn, mode);
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
}

void handleMain()
{
    INPUT_RECORD rcd;
    DWORD rcdnum;
    while (true)
    {
        ReadConsoleInputA(hIn, &rcd, 1, &rcdnum);
        if (rcd.EventType == KEY_EVENT)
        {
            if (rcd.Event.KeyEvent.bKeyDown)
            {
                WORD keycode = rcd.Event.KeyEvent.wVirtualKeyCode;
                if (keycode == VK_UP || keycode == VK_LEFT)
                {
                    selectPage(true, &pageIndex, hOut);
                }
                else if(keycode == VK_DOWN || keycode == VK_RIGHT)
                {
                    selectPage(false, &pageIndex, hOut);
                }
                else if (keycode >= 0x31 && keycode <= N_CMD + 0x30)
                {
                    keycode -= 0x31;
                    command[keycode]();
                }
                else if (keycode >= VK_NUMPAD1 && keycode <= N_CMD + VK_NUMPAD0)
                {
                    keycode -= VK_NUMPAD1;
                    command[keycode]();
                }
                else if (keycode == VK_ESCAPE)
                {
                    cmdExit();
                }
            }
        }
    }
}

void handleSort()
{
    INPUT_RECORD rcd;
    DWORD rcdnum;
    while (true)
    {
        ReadConsoleInputA(hIn, &rcd, 1, &rcdnum);
        if (rcd.EventType == KEY_EVENT)
        {
            if (rcd.Event.KeyEvent.bKeyDown)
            {
                WORD keycode = rcd.Event.KeyEvent.wVirtualKeyCode;
                if (keycode == VK_UP || keycode == VK_LEFT)
                {
                    selectPage(true, &pageIndex, hOut);
                    continue;
                }
                else if(keycode == VK_DOWN || keycode == VK_RIGHT)
                {
                    selectPage(false, &pageIndex, hOut);
                    continue;
                }
                else if(keycode == VK_ESCAPE)
                {
                    return;
                }
                else if (keycode >= '1' && keycode <= '6')
                {
                    keycode -= '0';   
                }
                else if (keycode >= VK_NUMPAD1 && keycode <= VK_NUMPAD6)
                {
                    keycode -= VK_NUMPAD0;
                }
                else
                {
                    continue;
                }
                Criteria order = keycode >> 2;
                //位运算获得排序对象准则
                Criteria obj = keycode <= 3 ? keycode << 1 : ((keycode + 1) & 0b011) << 1;
                cmdSort(order | obj);
                clearScreenRect(5, 5 + N_LIST);
                printData(locatePage(&pageIndex), pageIndex);
            }
        }
    
    }
}

void showHeader()
{
    printf("=========================================================\n");
    printf("=              账   户   管   理   系   统              =\n");
    printf("=========================================================\n");
}

void showPageMain()
{
    for (int i = 0; i < 4; ++i)
    {
        for (int j = 0; j < 2; ++j)
        {
            cursorPos(POS_X[i], POS_Y[j]);
            printf("┌-----------┐");
            cursorPos(POS_X[i], POS_Y[j] + 2);
            printf("└-----------┘");
        }
    }
    cursorPos(POS_X[0], POS_Y[0] + 1);
    printf("| 1. 查  询 |");
    cursorPos(POS_X[1], POS_Y[0] + 1);
    printf("| 2. 排  序 |");
    cursorPos(POS_X[2], POS_Y[0] + 1);
    printf("| 3. 写  入 |");
    cursorPos(POS_X[3], POS_Y[0] + 1);
    printf("| 4. 删  除 |");
    cursorPos(POS_X[0], POS_Y[1] + 1);
    printf("| 5. 存  款 |");
    cursorPos(POS_X[1], POS_Y[1] + 1);
    printf("| 6. 取  款 |");
    cursorPos(POS_X[2], POS_Y[1] + 1);
    printf("| 7. 转  账 |");
    cursorPos(POS_X[3], POS_Y[1] + 1);
    printf("| 8. 退  出 |");
    cursorPos(0, 3);
    showListHeader();
    printData(locatePage(&pageIndex), pageIndex);
}

void showPageSearch()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("查   询\n");
    cmdSearch();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void showPageSort()
{
    clearCommandRect();
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 2; ++j)
        {
            cursorPos(POS_X[i], POS_Y[j]);
            printf("┌------------┐");
            cursorPos(POS_X[i], POS_Y[j] + 2);
            printf("└------------┘");
        }
    }
    cursorPos(POS_X[0], POS_Y[0] + 1);
    printf("| 1.学号升序 |");
    cursorPos(POS_X[1], POS_Y[0] + 1);
    printf("| 2.姓名升序 |");
    cursorPos(POS_X[2], POS_Y[0] + 1);
    printf("| 3.余额升序 |");
    cursorPos(POS_X[0], POS_Y[1] + 1);
    printf("| 4.学号降序 |");
    cursorPos(POS_X[1], POS_Y[1] + 1);
    printf("| 5.姓名降序 |");
    cursorPos(POS_X[2], POS_Y[1] + 1);
    printf("| 6.余额降序 |");
    cursorPos(X_RETURN, Y_RETURN);
    printf("┌------------┐");
    cursorPos(X_RETURN, Y_RETURN + 1);
    printf("|  ESC.返回  |");
    cursorPos(X_RETURN, Y_RETURN + 2);
    printf("└------------┘");
    cursorPos(0, 3);
    handleSort();
    clearContentRect();
    showPageMain();
}

void showPageWrite()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("写   入\n");
    cmdWrite();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void showPageDelete()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("删   除\n");
    cmdDelete();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void showPageDeposit()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("存   款\n");
    cmdDeposit();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void showPageWithdraw()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("取   款\n");
    cmdWithdraw();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void showPageTransfer()
{
    clearContentRect();
    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOut, &cci);
    cci.bVisible = true;
    SetConsoleCursorInfo(hOut, &cci);
    cursorPos(25, 3);
    printf("转   账\n");
    cmdTransfer();
    cci.bVisible = false;
    SetConsoleCursorInfo(hOut, &cci);
    clearPageRect();
    showPageMain();
}

void cursorPos(short x, short y)
{
    COORD coord = {x, y};
    SetConsoleCursorPosition(hOut, coord);
}

void clearPageRect()
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
    COORD coord = {0, 3};
    DWORD length = csbi.dwSize.X * (csbi.dwSize.Y - 10);
    DWORD count;
    FillConsoleOutputCharacterA(hOut, ' ', length, coord, &count);
    coord.Y = 3;
    SetConsoleCursorPosition(hOut, coord);
}

void clearScreenRect(short from, short to)
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
    COORD coord = {0, from};
    DWORD length = csbi.dwSize.X * (to - from);
    DWORD count;
    FillConsoleOutputCharacterA(hOut, ' ', length, coord, &count);
    SetConsoleCursorPosition(hOut, coord);
}

void clearContentRect()
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
    COORD coord = {0, 3};
    DWORD length = csbi.dwSize.X * (csbi.dwSize.Y - 3);
    DWORD count;
    FillConsoleOutputCharacterA(hOut, ' ', length, coord, &count);
    SetConsoleCursorPosition(hOut, coord);
}

void clearCommandRect()
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);
    COORD coord = {0, 21};
    DWORD length = csbi.dwSize.X * (csbi.dwSize.Y - 6);
    DWORD count;
    FillConsoleOutputCharacterA(hOut, ' ', length, coord, &count);
    SetConsoleCursorPosition(hOut, coord);
}

void showListHeader()
{
    cursorPos(0, 3);
    printf("  序号   |     学号     |     姓名     |       存款\n");
    printf("---------------------------------------------------------\n");
    cursorPos(0, 20);
    printf("---------------------------------------------------------\n");
    cursorPos(0, 5);
}

void shutdownView()
{
    CloseHandle(hIn);
    CloseHandle(hOut);
}